/*******************************************************************
 *
 * Copyright (C), 2021-2022, Letstrong, All rights reserved.
 *
 * Author      : 
 * Create Time : 2020-12-14
 * Version     : v0.1
 * Description : 
 *******************************************************************/

/*----------------------------Head file----------------------------*/
#include "rwip_config.h"

#if (BLE_OTA_SERVER)
#include "attm.h"
#include "ota.h"
#include "ota_task.h"
#include "ke_mem.h"
#include "prf_utils.h"
#include "prf.h"
#include "co_utils.h"
#include "flash.h"
#include "ke.h"
#include "icu.h"
#include "wdt.h"
#include "gapc_task.h"

#define OTA_LOG_ENABLE      0

#if OTA_LOG_ENABLE
#include "log.h"
#define OTA_LOG             LOG_DEBUG
#else
#define OTA_LOG(...)
#endif

/*----------------------------macro file---------------------------*/
//#define OTA_BASE_UUID_128(uuid)		{0x23, 0xD1, 0xBC, 0xEA, 0x5F, 0x78, 0x23, 0x15, 0xDE, 0xEF, 0x12, 0x12, LO_UINT16(uuid), HI_UINT16( uuid ), 0x00, 0x00}
#define OTA_BASE_UUID_128(uuid)		{0x12, 0xD5, 0xBC, 0xEA, 0x5F, 0x98, 0x23, 0x23, 0xDE, 0xEF, 0xAA, 0x55, LO_UINT16(uuid), HI_UINT16( uuid ), 0x00, 0x00}
#define BASE_ATT_UUID_128(uuid)		{LO_UINT16( uuid ), HI_UINT16( uuid ), 0x93, 0xA6, 0xBD, 0xD8, 0x41, 0x52, 0xAC, 0x0B, 0x10, 0x99, 0x2E, 0xC6, 0xFE, 0xED}

#define ATT128_DECL_PRIMARY_SERVICE			BASE_ATT_UUID_128(ATT_DECL_PRIMARY_SERVICE)
#define ATT128_DECL_CHARACTERISTIC			BASE_ATT_UUID_128(ATT_DECL_CHARACTERISTIC)
#define ATT128_DESC_CLIENT_CHAR_CFG			BASE_ATT_UUID_128(ATT_DESC_CLIENT_CHAR_CFG)
#define ATT128_DESC_CHAR_USER_DESCRIPTION	BASE_ATT_UUID_128(ATT_DESC_CHAR_USER_DESCRIPTION)

/*#define ATT128_CHAR_CTRL_POINT				OTA_BASE_UUID_128(0x1531)
#define ATT128_CHAR_PACKET					OTA_BASE_UUID_128(0x1532)
#define ATT128_CHAR_VERSION					OTA_BASE_UUID_128(0x1534)*/

#define ATT128_CHAR_CTRL_POINT				OTA_BASE_UUID_128(0x5631)
#define ATT128_CHAR_PACKET					OTA_BASE_UUID_128(0x5632)
#define ATT128_CHAR_VERSION					OTA_BASE_UUID_128(0x5633)

/*----------------------------type define--------------------------*/
typedef uint8_t att_svc_desc128_t[ATT_UUID_128_LEN];
											
/*----------------------------var define---------------------------*/							
//static const att_svc_desc128_t ota_svc = OTA_BASE_UUID_128(0x1530);
	static const att_svc_desc128_t ota_svc = OTA_BASE_UUID_128(0x5630);

struct attm_desc_128 ota_att_db[OTA_IDX_NB] = 
{
	// OTA Service Declaration
	[OTA_IDX_SVC] = {ATT128_DECL_PRIMARY_SERVICE, PERM(RD, ENABLE), 0, 0},

	[OTA_IDX_CTRL_POINT_CHAR] = {ATT128_DECL_CHARACTERISTIC, PERM(RD, ENABLE), 0, 0},
	[OTA_IDX_CTRL_POINT_VAL] = {ATT128_CHAR_CTRL_POINT, PERM(WRITE_REQ, ENABLE) | PERM(NTF, ENABLE), PERM(RI, ENABLE) | PERM(UUID_LEN, UUID_128) | ATT_UUID_128_LEN, OTA_TRANSFER_DATA_MAX_LEN *sizeof(uint8_t)},
	[OTA_IDX_CTRL_POINT_NTF_CFG] = {ATT128_DESC_CLIENT_CHAR_CFG, PERM(RD, ENABLE) | PERM(WRITE_REQ, ENABLE), 0, 0},
	
	[OTA_IDX_PACKET_CHAR] = {ATT128_DECL_CHARACTERISTIC, PERM(RD, ENABLE), 0, 0},
	[OTA_IDX_PACKET_VAL] = {ATT128_CHAR_PACKET, PERM(WRITE_COMMAND, ENABLE), PERM(RI, ENABLE) | PERM(UUID_LEN, UUID_128) | ATT_UUID_128_LEN, OTA_TRANSFER_DATA_MAX_LEN *sizeof(uint8_t)},
	
	[OTA_IDX_VERSION_CHAR] = {ATT128_DECL_CHARACTERISTIC, PERM(RD, ENABLE), 0, 0},
	[OTA_IDX_VERSION_VAL] = {ATT128_CHAR_VERSION, PERM(RD, ENABLE), PERM(RI, ENABLE) | PERM(UUID_LEN, UUID_128) | ATT_UUID_128_LEN, OTA_TRANSFER_DATA_MAX_LEN *sizeof(uint8_t)},
};

/*-------------------------func declaration------------------------*/

/*-----------------------------------------------------------------*/

static uint8_t ota_init(struct prf_task_env* env, uint16_t* start_hdl, uint16_t app_task, uint8_t sec_lvl,  struct ota_db_cfg* params)
{
	// Service content flag
	uint32_t cfg_flag = OTA_MANDATORY_MASK;
	// DB Creation Status
	uint8_t status = ATT_ERR_NO_ERROR;

	status = attm_svc_create_db_128(start_hdl, (uint8_t*)&ota_svc, (uint8_t *)&cfg_flag,
				OTA_IDX_NB, NULL, env->task, &ota_att_db[OTA_IDX_SVC],
				(sec_lvl & (PERM_MASK_SVC_DIS | PERM_MASK_SVC_AUTH | PERM_MASK_SVC_EKS | PERM_MASK_SVC_UUID_LEN)));

	//And need to set req->sec_lvl = 0x40; //PERM_MASK_SVC_UUID_LEN 128 bit in app_ota_add()
	
	if(status == ATT_ERR_NO_ERROR)
	{
		struct ota_env_tag* ota_env = (struct ota_env_tag* ) ke_malloc(sizeof(struct ota_env_tag), KE_MEM_ATT_DB);
		env->env = (prf_env_t*) ota_env;

		// set start handle to first allocated service value
		ota_env->start_hdl         = *start_hdl;
		ota_env->features          = params->features;
		ota_env->prf_env.app_task  = app_task | (PERM_GET(sec_lvl, SVC_MI) ? PERM(PRF_MI, ENABLE) : PERM(PRF_MI, DISABLE));
		ota_env->prf_env.prf_task  = env->task | PERM(PRF_MI, DISABLE);

		// initialize environment variable
		env->id                     = TASK_ID_OTA;
		env->desc.idx_max           = OTA_IDX_MAX;
		env->desc.state             = ota_env->state;
		env->desc.default_handler   = &ota_default_handler;

		memset(ota_env->ctrl_point_ntf_cfg, 0, BLE_CONNECTION_MAX);
		
		// service is ready, go into an Idle state
		ke_state_set(env->task, OTA_IDLE);
	}
	return (status);
}


static void ota_destroy(struct prf_task_env* env)
{
	struct ota_env_tag* ota_env = (struct ota_env_tag*) env->env;  

	// clear on-going operation
	if(ota_env->operation != NULL)
	{
		ke_free(ota_env->operation);
	}

	// free profile environment variables
	env->env = NULL;
	ke_free(ota_env);
}

static void ota_create(struct prf_task_env* env, uint8_t conidx)
{
	struct ota_env_tag* ota_env = (struct ota_env_tag*) env->env;
	ASSERT_ERR(conidx < BLE_CONNECTION_MAX);

	// force notification config to zero when peer device is connected
	ota_env->ctrl_point_ntf_cfg[conidx] = 0;
}


static void ota_cleanup(struct prf_task_env* env, uint8_t conidx, uint8_t reason)
{
	struct ota_env_tag* ota_env = (struct ota_env_tag*) env->env;

	ASSERT_ERR(conidx < BLE_CONNECTION_MAX);
	// force notification config to zero when peer device is disconnected
	ota_env->ctrl_point_ntf_cfg[conidx] = 0;
}


uint16_t ota_get_att_handle(uint8_t att_idx)
{
	struct ota_env_tag *ota_env = PRF_ENV_GET(OTA, ota);
	uint16_t handle = ATT_INVALID_HDL;

	handle = ota_env->start_hdl;

	// increment index according to expected index
	if(att_idx < OTA_IDX_NB) {
		handle += att_idx;
	}
	else {
		handle = ATT_INVALID_HDL;
	}

	return handle;
}


void ota_ctrl_point_notify(struct ota_ctrl_point_ntf const *param)
{
	struct ota_env_tag* ota_env = PRF_ENV_GET(OTA, ota);

	// Allocate the GATT notification message
	struct gattc_send_evt_cmd *send_lvl = KE_MSG_ALLOC_DYN(GATTC_SEND_EVT_CMD,
			KE_BUILD_ID(TASK_GATTC, 0),  prf_src_task_get(&(ota_env->prf_env), 0),
			gattc_send_evt_cmd, sizeof(uint8_t)* OTA_TRANSFER_DATA_MAX_LEN);

	// Fill in the parameter structure
	send_lvl->operation = GATTC_NOTIFY;
	send_lvl->handle = ota_get_att_handle(OTA_IDX_CTRL_POINT_VAL);
	// pack measured value in database
	send_lvl->length = param->len;
	memcpy(&send_lvl->value[0], &param->value[0], param->len);
	// send notification to peer device
	ke_msg_send(send_lvl);
}


/// OTA Task interface required by profile manager
const struct prf_task_cbs ota_itf =
{
	(prf_init_fnct) ota_init,
	ota_destroy,
	ota_create,
	ota_cleanup,
};


const struct prf_task_cbs* ota_prf_itf_get(void)
{
	return &ota_itf;
}


#endif // (BLE_OTA_SERVER)

